#ifndef ULTRA64_R4300_H
#define ULTRA64_R4300_H

#ifdef _LANGUAGE_C
#include "ultratypes.h"
#define U32(x) ((u32)x)
#else
#define U32(x) (x)
#endif

/* Segment base addresses and sizes */
#define KUBASE      0
#define KUSIZE      0x80000000
#define K0BASE      0x80000000
#define K0SIZE      0x20000000
#define K1BASE      0xA0000000
#define K1SIZE      0x20000000
#define K2BASE      0xC0000000
#define K2SIZE      0x20000000

/* Exception vectors */
#define SIZE_EXCVEC 0x80                    /* Size of an exc. vec */
#define UT_VEC      K0BASE                  /* utlbmiss vector */
#define R_VEC       (K1BASE + 0x1FC00000)   /* reset vector */
#define XUT_VEC     (K0BASE + 0x80)         /* extended address tlbmiss */
#define ECC_VEC     (K0BASE + 0x100)        /* Ecc exception vector */
#define E_VEC       (K0BASE + 0x180)        /* Gen. exception vector */

/* Address conversion macros */
#define K0_TO_K1(x)     (U32(x) | 0xA0000000)  /* kseg0 to kseg1 */
#define K1_TO_K0(x)     (U32(x) & 0x9FFFFFFF)  /* kseg1 to kseg0 */
#define K0_TO_PHYS(x)   (U32(x) & 0x1FFFFFFF)  /* kseg0 to physical */
#define K1_TO_PHYS(x)   (U32(x) & 0x1FFFFFFF)  /* kseg1 to physical */
#define KDM_TO_PHYS(x)  (U32(x) & 0x1FFFFFFF)  /* direct mapped to physical */
#define PHYS_TO_K0(x)   (U32(x) | 0x80000000)  /* physical to kseg0 */
#define PHYS_TO_K1(x)   (U32(x) | 0xA0000000)  /* physical to kseg1 */

/* Address predicates */
#define IS_KSEG0(x)     (U32(x) >= K0BASE && U32(x) < K1BASE)
#define IS_KSEG1(x)     (U32(x) >= K1BASE && U32(x) < K2BASE)
#define IS_KSEGDM(x)    (U32(x) >= K0BASE && U32(x) < K2BASE)
#define IS_KSEG2(x)     (U32(x) >= K2BASE && U32(x) < KPTE_SHDUBASE)
#define IS_KPTESEG(x)   (U32(x) >= KPTE_SHDUBASE)
#define IS_KUSEG(x)     (U32(x) < K0BASE)

/* TLB size constants */
#define NTLBENTRIES 31      /* entry 31 is reserved by rdb */

#define TLBHI_VPN2MASK      0xFFFFE000
#define TLBHI_VPN2SHIFT     13
#define TLBHI_PIDMASK       0xFF
#define TLBHI_PIDSHIFT      0
#define TLBHI_NPID          255         /* 255 to fit in 8 bits */

#define TLBLO_PFNMASK       0x3FFFFFC0
#define TLBLO_PFNSHIFT      6
#define TLBLO_CACHMASK      0x38        /* cache coherency algorithm */
#define TLBLO_CACHSHIFT     3
#define TLBLO_UNCACHED      0x10        /* not cached */
#define TLBLO_NONCOHRNT     0x18        /* Cacheable non-coherent */
#define TLBLO_EXLWR         0x28        /* Exclusive write */
#define TLBLO_D             0x4         /* writeable */
#define TLBLO_V             0x2         /* valid bit */
#define TLBLO_G             0x1         /* global access bit */

#define TLBINX_PROBE        0x80000000
#define TLBINX_INXMASK      0x3F
#define TLBINX_INXSHIFT     0

#define TLBRAND_RANDMASK    0x3F
#define TLBRAND_RANDSHIFT   0

#define TLBWIRED_WIREDMASK  0x3F

#define TLBCTXT_BASEMASK    0xFF800000
#define TLBCTXT_BASESHIFT   23
#define TLBCTXT_BASEBITS    9

#define TLBCTXT_VPNMASK     0x7FFFF0
#define TLBCTXT_VPNSHIFT    4

#define TLBPGMASK_4K        0x0
#define TLBPGMASK_16K       0x6000
#define TLBPGMASK_64K       0x1E000

/*
 * Status register
 */
#define SR_CUMASK   0xF0000000  /* coproc usable bits */

#define SR_CU3      0x80000000  /* Coprocessor 3 usable */
#define SR_CU2      0x40000000  /* Coprocessor 2 usable */
#define SR_CU1      0x20000000  /* Coprocessor 1 usable */
#define SR_CU0      0x10000000  /* Coprocessor 0 usable */
#define SR_RP       0x08000000  /* Reduced power (quarter speed) */
#define SR_FR       0x04000000  /* MIPS III FP register mode */
#define SR_RE       0x02000000  /* Reverse endian */
#define SR_ITS      0x01000000  /* Instruction trace support */
#define SR_BEV      0x00400000  /* Use boot exception vectors */
#define SR_TS       0x00200000  /* TLB shutdown */
#define SR_SR       0x00100000  /* Soft reset occured */
#define SR_CH       0x00040000  /* Cache hit for last 'cache' op */
#define SR_CE       0x00020000  /* Create ECC */
#define SR_DE       0x00010000  /* ECC of parity does not cause error */

/* Interrupt enable bits */
/* (NOTE: bits set to 1 enable the corresponding level interrupt) */
#define SR_IMASK    0x0000FF00  /* Interrupt mask */
#define SR_IMASK8   0x00000000  /* mask level 8 */
#define SR_IMASK7   0x00008000  /* mask level 7 */
#define SR_IMASK6   0x0000C000  /* mask level 6 */
#define SR_IMASK5   0x0000E000  /* mask level 5 */
#define SR_IMASK4   0x0000F000  /* mask level 4 */
#define SR_IMASK3   0x0000F800  /* mask level 3 */
#define SR_IMASK2   0x0000FC00  /* mask level 2 */
#define SR_IMASK1   0x0000FE00  /* mask level 1 */
#define SR_IMASK0   0x0000FF00  /* mask level 0 */

#define SR_IBIT8    0x00008000  /* bit level 8 */
#define SR_IBIT7    0x00004000  /* bit level 7 */
#define SR_IBIT6    0x00002000  /* bit level 6 */
#define SR_IBIT5    0x00001000  /* bit level 5 */
#define SR_IBIT4    0x00000800  /* bit level 4 */
#define SR_IBIT3    0x00000400  /* bit level 3 */
#define SR_IBIT2    0x00000200  /* bit level 2 */
#define SR_IBIT1    0x00000100  /* bit level 1 */

#define SR_IMASKSHIFT   8

#define SR_KX       0x00000080  /* extended-addr TLB vec in kernel */
#define SR_SX       0x00000040  /* xtended-addr TLB vec supervisor */
#define SR_UX       0x00000020  /* xtended-addr TLB vec in user mode */
#define SR_KSU_MASK 0x00000018  /* mode mask */
#define SR_KSU_USR  0x00000010  /* user mode */
#define SR_KSU_SUP  0x00000008  /* supervisor mode */
#define SR_KSU_KER  0x00000000  /* kernel mode */
#define SR_ERL      0x00000004  /* Error level, 1=>cache error */
#define SR_EXL      0x00000002  /* Exception level, 1=>exception */
#define SR_IE       0x00000001  /* interrupt enable, 1=>enable */

/* Cause Register */
#define CAUSE_BD        0x80000000  /* Branch delay slot */
#define CAUSE_CEMASK    0x30000000  /* coprocessor error */
#define CAUSE_CESHIFT   28

/* Interrupt pending bits */
#define CAUSE_IP8   0x00008000  /* External level 8 pending - COMPARE */
#define CAUSE_IP7   0x00004000  /* External level 7 pending - INT4 */
#define CAUSE_IP6   0x00002000  /* External level 6 pending - INT3 */
#define CAUSE_IP5   0x00001000  /* External level 5 pending - INT2 */
#define CAUSE_IP4   0x00000800  /* External level 4 pending - INT1 */
#define CAUSE_IP3   0x00000400  /* External level 3 pending - INT0 */
#define CAUSE_SW2   0x00000200  /* Software level 2 pending */
#define CAUSE_SW1   0x00000100  /* Software level 1 pending */

#define CAUSE_IPMASK    0x0000FF00  /* Pending interrupt mask */
#define CAUSE_IPSHIFT   8

#define CAUSE_EXCMASK   0x0000007C  /* Cause code bits */
#define CAUSE_EXCSHIFT  2

/* Cause register exception codes */

#define EXC_CODE(x) ((x) << 2)

/* Hardware exception codes */
#define EXC_INT     EXC_CODE(0)     /* interrupt */
#define EXC_MOD     EXC_CODE(1)     /* TLB mod */
#define EXC_RMISS   EXC_CODE(2)     /* Read TLB Miss */
#define EXC_WMISS   EXC_CODE(3)     /* Write TLB Miss */
#define EXC_RADE    EXC_CODE(4)     /* Read Address Error */
#define EXC_WADE    EXC_CODE(5)     /* Write Address Error */
#define EXC_IBE     EXC_CODE(6)     /* Instruction Bus Error */
#define EXC_DBE     EXC_CODE(7)     /* Data Bus Error */
#define EXC_SYSCALL EXC_CODE(8)     /* SYSCALL */
#define EXC_BREAK   EXC_CODE(9)     /* BREAKpoint */
#define EXC_II      EXC_CODE(10)    /* Illegal Instruction */
#define EXC_CPU     EXC_CODE(11)    /* CoProcessor Unusable */
#define EXC_OV      EXC_CODE(12)    /* OVerflow */
#define EXC_TRAP    EXC_CODE(13)    /* Trap exception */
#define EXC_VCEI    EXC_CODE(14)    /* Virt. Coherency on Inst. fetch */
#define EXC_FPE     EXC_CODE(15)    /* Floating Point Exception */
#define EXC_WATCH   EXC_CODE(23)    /* Watchpoint reference */
#define EXC_VCED    EXC_CODE(31)    /* Virt. Coherency on data read */

/* C0_PRID Defines */
#define C0_IMPMASK      0xFF00
#define C0_IMPSHIFT     8
#define C0_REVMASK      0xFF
#define C0_MAJREVMASK   0xF0
#define C0_MAJREVSHIFT  4
#define C0_MINREVMASK   0xF

/* Coprocessor 0 operations */
#define C0_READI    0x1     /* read ITLB entry addressed by C0_INDEX */
#define C0_WRITEI   0x2     /* write ITLB entry addressed by C0_INDEX */
#define C0_WRITER   0x6     /* write ITLB entry addressed by C0_RAND */
#define C0_PROBE    0x8     /* probe for ITLB entry addressed by TLBHI */
#define C0_RFE      0x10    /* restore for exception */

/* 'cache' instruction definitions */

/* Target cache */
#define CACH_PI     0x0     /* specifies primary inst. cache */
#define CACH_PD     0x1     /* primary data cache */
#define CACH_SI     0x2     /* secondary instruction cache */
#define CACH_SD     0x3     /* secondary data cache */

/* Cache operations */
#define C_IINV      0x0     /* index invalidate (inst, 2nd inst) */
#define C_IWBINV    0x0     /* index writeback inval (d, sd) */
#define C_ILT       0x4     /* index load tag (all) */
#define C_IST       0x8     /* index store tag (all) */
#define C_CDX       0xC     /* create dirty exclusive (d, sd) */
#define C_HINV      0x10    /* hit invalidate (all) */
#define C_HWBINV    0x14    /* hit writeback inv. (d, sd) */
#define C_FILL      0x14    /* fill (i) */
#define C_HWB       0x18    /* hit writeback (i, d, sd) */
#define C_HSV       0x1C    /* hit set virt. (si, sd) */

/* Cache size definitions */
#define ICACHE_SIZE         0x4000      /* 16K */
#define ICACHE_LINESIZE     32          /* 8 words */
#define ICACHE_LINEMASK     (ICACHE_LINESIZE - 1)

#define DCACHE_SIZE         0x2000      /* 8K */
#define DCACHE_LINESIZE     16          /* 4 words */
#define DCACHE_LINEMASK     (DCACHE_LINESIZE - 1)

/* C0_CONFIG register definitions */
#define CONFIG_CM       0x80000000      /* 1 == Master-Checker enabled */
#define CONFIG_EC       0x70000000      /* System Clock ratio */
#define CONFIG_EC_1_1   0x6             /* System Clock ratio 1 :1 */
#define CONFIG_EC_3_2   0x7             /* System Clock ratio 1.5 :1 */
#define CONFIG_EC_2_1   0x0             /* System Clock ratio 2 :1 */
#define CONFIG_EC_3_1   0x1             /* System Clock ratio 3 :1 */
#define CONFIG_EP       0x0F000000      /* Transmit Data Pattern */
#define CONFIG_SB       0x00C00000      /* Secondary cache block size */

#define CONFIG_SS       0x00200000      /* Split scache: 0 == I&D combined */
#define CONFIG_SW       0x00100000      /* scache port: 0==128, 1==64 */
#define CONFIG_EW       0x000C0000      /* System Port width: 0==64, 1==32 */
#define CONFIG_SC       0x00020000      /* 0 -> 2nd cache present */
#define CONFIG_SM       0x00010000      /* 0 -> Dirty Shared Coherency enable */
#define CONFIG_BE       0x00008000      /* Endian-ness: 1 --> BE */
#define CONFIG_EM       0x00004000      /* 1 -> ECC mode, 0 -> parity */
#define CONFIG_EB       0x00002000      /* Block order:1->sequent,0->subblock */

#define CONFIG_IC       0x00000E00      /* Primary Icache size */
#define CONFIG_DC       0x000001C0      /* Primary Dcache size */
#define CONFIG_IB       0x00000020      /* Icache block size */
#define CONFIG_DB       0x00000010      /* Dcache block size */
#define CONFIG_CU       0x00000008      /* Update on Store-conditional */
#define CONFIG_K0       0x00000007      /* K0SEG Coherency algorithm */

#define CONFIG_UNCACHED     0x00000002  /* K0 is uncached */
#define CONFIG_NONCOHRNT    0x00000003
#define CONFIG_COHRNT_EXLWR 0x00000005
#define CONFIG_SB_SHFT      22          /* shift SB to bit position 0 */
#define CONFIG_IC_SHFT      9           /* shift IC to bit position 0 */
#define CONFIG_DC_SHFT      6           /* shift DC to bit position 0 */
#define CONFIG_BE_SHFT      15          /* shift BE to bit position 0 */

/* C0_TAGLO definitions for setting/getting cache states and physaddr bits */
#define SADDRMASK   0xFFFFE000  /* 31..13 -> scache paddr bits 35..17 */
#define SVINDEXMASK 0x00000380  /* 9..7: prim virt index bits 14..12 */
#define SSTATEMASK  0x00001C00  /* bits 12..10 hold scache line state */
#define SINVALID    0x00000000  /* invalid --> 000 == state 0 */
#define SCLEANEXCL  0x00001000  /* clean exclusive --> 100 == state 4 */
#define SDIRTYEXCL  0x00001400  /* dirty exclusive --> 101 == state 5 */
#define SECC_MASK   0x0000007F  /* low 7 bits are ecc for the tag */
#define SADDR_SHIFT 4           /* shift STagLo (31..13) to 35..17 */

#define PADDRMASK       0xFFFFFF00  /* PTagLo31..8->prim paddr bits35..12 */
#define PADDR_SHIFT     4           /* roll bits 35..12 down to 31..8 */
#define PSTATEMASK      0x00C0      /* bits 7..6 hold primary line state */
#define PINVALID        0x0000      /* invalid --> 000 == state 0 */
#define PCLEANEXCL      0x0080      /* clean exclusive --> 10 == state 2 */
#define PDIRTYEXCL      0x00C0      /* dirty exclusive --> 11 == state 3 */
#define PPARITY_MASK    0x0001      /* low bit is parity bit (even). */

/* C0_CACHE_ERR definitions. */
#define CACHERR_ER          0x80000000  /* 0: inst ref, 1: data ref */
#define CACHERR_EC          0x40000000  /* 0: primary, 1: secondary */
#define CACHERR_ED          0x20000000  /* 1: data error */
#define CACHERR_ET          0x10000000  /* 1: tag error */
#define CACHERR_ES          0x08000000  /* 1: external ref, e.g. snoo */
#define CACHERR_EE          0x04000000  /* error on SysAD bus */
#define CACHERR_EB          0x02000000  /* complicated, see spec. */
#define CACHERR_EI          0x01000000  /* complicated, see spec. */
#define CACHERR_SIDX_MASK   0x003FFFF8  /* secondary cache index */
#define CACHERR_PIDX_MASK   0x00000007  /* primary cache index */
#define CACHERR_PIDX_SHIFT  12          /* bits 2..0 are paddr14..12 */

/*
 * R4000 family supports hardware watchpoints:
 *   C0_WATCHLO:
 *     bits 31..3 are bits 31..3 of physaddr to watch
 *     bit 2:  reserved; must be written as 0.
 *     bit 1:  when set causes a watchpoint trap on load accesses to paddr.
 *     bit 0:  when set traps on stores to paddr;
 *   C0_WATCHHI
 *     bits 31..4 are reserved and must be written as zeros.
 *     bits 3..0 are bits 35..32 of the physaddr to watch
 */
#define WATCHLO_WTRAP       0x00000001
#define WATCHLO_RTRAP       0x00000002
#define WATCHLO_ADDRMASK    0xFFFFFFF8
#define WATCHLO_VALIDMASK   0xFFFFFFFB
#define WATCHHI_VALIDMASK   0x0000000F

/* Coprocessor 0 registers */
#ifdef _LANGUAGE_C
#define C0_INX          0
#define C0_RAND         1
#define C0_ENTRYLO0     2
#define C0_ENTRYLO1     3
#define C0_CONTEXT      4
#define C0_PAGEMASK     5       /* page mask                        */
#define C0_WIRED        6       /* # wired entries in tlb           */
#define C0_BADVADDR     8
#define C0_COUNT        9       /* free-running counter             */
#define C0_ENTRYHI      10
#define C0_COMPARE      11      /* counter comparison reg.          */
#define C0_SR           12
#define C0_CAUSE        13
#define C0_EPC          14
#define C0_PRID         15      /* revision identifier              */
#define C0_CONFIG       16      /* hardware configuration           */
#define C0_LLADDR       17      /* load linked address              */
#define C0_WATCHLO      18      /* watchpoint                       */
#define C0_WATCHHI      19      /* watchpoint                       */
#define C0_ECC          26      /* S-cache ECC and primary parity   */
#define C0_CACHE_ERR    27      /* cache error status               */
#define C0_TAGLO        28      /* cache operations                 */
#define C0_TAGHI        29      /* cache operations                 */
#define C0_ERROR_EPC    30      /* ECC error prg. counter           */
#else
#define C0_INX          $0
#define C0_RAND         $1
#define C0_ENTRYLO0     $2
#define C0_ENTRYLO1     $3
#define C0_CONTEXT      $4
#define C0_PAGEMASK     $5      /* page mask                        */
#define C0_WIRED        $6      /* # wired entries in tlb           */
#define C0_BADVADDR     $8
#define C0_COUNT        $9      /* free-running counter             */
#define C0_ENTRYHI      $10
#define C0_COMPARE      $11     /* counter comparison reg.          */
#define C0_SR           $12
#define C0_CAUSE        $13
#define C0_EPC          $14
#define C0_PRID         $15     /* revision identifier              */
#define C0_CONFIG       $16     /* hardware configuration           */
#define C0_LLADDR       $17     /* load linked address              */
#define C0_WATCHLO      $18     /* watchpoint                       */
#define C0_WATCHHI      $19     /* watchpoint                       */
#define C0_ECC          $26     /* S-cache ECC and primary parity   */
#define C0_CACHE_ERR    $27     /* cache error status               */
#define C0_TAGLO        $28     /* cache operations                 */
#define C0_TAGHI        $29     /* cache operations                 */
#define C0_ERROR_EPC    $30     /* ECC error prg. counter           */
#endif

/* floating-point status register */
#ifdef _LANGUAGE_C
#define C1_FPCSR        31
#else
#define C1_FPCSR        $31
#endif

#define FPCSR_FS        0x01000000  /* flush denorm to zero             */
#define FPCSR_C         0x00800000  /* condition bit                    */
#define FPCSR_CE        0x00020000  /* cause: unimplemented operation   */
#define FPCSR_CV        0x00010000  /* cause: invalid operation         */
#define FPCSR_CZ        0x00008000  /* cause: division by zero          */
#define FPCSR_CO        0x00004000  /* cause: overflow                  */
#define FPCSR_CU        0x00002000  /* cause: underflow                 */
#define FPCSR_CI        0x00001000  /* cause: inexact operation         */
#define FPCSR_EV        0x00000800  /* enable: invalid operation        */
#define FPCSR_EZ        0x00000400  /* enable: division by zero         */
#define FPCSR_EO        0x00000200  /* enable: overflow                 */
#define FPCSR_EU        0x00000100  /* enable: underflow                */
#define FPCSR_EI        0x00000080  /* enable: inexact operation        */
#define FPCSR_FV        0x00000040  /* flag: invalid operation          */
#define FPCSR_FZ        0x00000020  /* flag: division by zero           */
#define FPCSR_FO        0x00000010  /* flag: overflow                   */
#define FPCSR_FU        0x00000008  /* flag: underflow                  */
#define FPCSR_FI        0x00000004  /* flag: inexact operation          */
#define FPCSR_RM_MASK   0x00000003  /* rounding mode mask               */
#define FPCSR_RM_RN     0x00000000  /* round to nearest                 */
#define FPCSR_RM_RZ     0x00000001  /* round to zero                    */
#define FPCSR_RM_RP     0x00000002  /* round to positive infinity       */
#define FPCSR_RM_RM     0x00000003  /* round to negative infinity       */

#endif
